R语言笔记8:两个重要函数——用来分解数据框的split和用来查看对象的str
R语言基础系列:
split()
split()
不是一个循环函数,但它和lapply()
还有sapply()
等一起使用起来很方便。
split()
的参数是一个向量,和tapply()
类似,但是并不计算概括统计量。它所做的是接收一个向量或对象x,然后接收一个因子变量f,f用来指定分组的水平(level),x根据f进行分组,分组之后返回一个列表,我们就可以对这些独立的组使用lapply()
或者sapply()
了
> str(split)
function (x, f, drop = FALSE, ...)
举例,和前一节的tapply()
类似,生成三组随机数,然后通过split()
进行分组,
因子变量设置为3,将x向量分解成3组,可以得到以下这个列表,三个元素:
> x <- c(rnorm(10), runif(10),rnorm(10,1))
> f<- gl(3,10)
> split(x,f)
$`1`
[1] 0.5370274 -0.8772336 -0.1203692 -1.6985533 -0.6796235
[6] -1.0284270 1.9282473 0.5562795 0.2560315 0.1244326
$`2`
[1] 0.88297485 0.56093613 0.98450850 0.05455810 0.43596680
[6] 0.01397831 0.41145110 0.43259515 0.85048958 0.10283914
$`3`
[1] 3.0159349 0.3021140 0.7565265 1.4841716 1.2435489
[6] 1.6161955 1.3092779 1.2535495 1.1271382 1.0764003
分组之后使用循环函数lapply()
或者sapply()
,求每个组中的统计值
结合起来用是这样的:
> lapply(split(x,f),mean)
$`1`
[1] -0.1107231
$`2`
[1] 0.6810998
$`3`
[1] 1.115751
其实,在这个例子中我们大可不必使用split
,因为tapply()
也可以达到完全一样的效果,而且会更加紧凑
split()
最大的好处是它可以用于分解数据框
↓
Splitting a Data Frame
以datasets数据集中的空气质量(airquality)数据集为例,可以看到数据集中包含臭氧、太阳辐射、风力、温度等测量值,以及月份、日期两个测量时间:
> library(datasets)
> head(airquality)
Ozone Solar.R Wind Temp Month Day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
4 18 313 11.5 62 5 4
5 NA NA 14.3 56 5 5
6 28 NA 14.9 66 5 6
假如我们想计算臭氧、辐射、风力、温度等测量值在某个月份内的平均值,那就要先使用split
对数据进行分类:
首先将整个数据框按月分组,将f因子设置为离散型变量
month
:
> s <- split(airquality, airquality$Month)
然后使用
lapply()
计算不同列的均值,其中使用匿名函数function(x)
,计算三个变量的均值:
> lapply(s, function(x) {colMeans(x[, c("Ozone", "Solar.R", "Wind")])})
$`5`
Ozone Solar.R Wind
NA NA 11.62258
$`6`
Ozone Solar.R Wind
NA 190.16667 10.26667
$`7`
Ozone Solar.R Wind
NA 216.483871 8.941935
$`8`
Ozone Solar.R Wind
NA NA 8.793548
$`9`
Ozone Solar.R Wind
NA 167.4333 10.1800
可以看到结果中lapply()
对每个月份都返回了一个列表,列表中的每个元素是一个长度为3的向量,代表三个变量在这个月中的均值。
lapply()
的缺点是以列表的形式返回的数据不够紧凑。因为每个向量长度都是3,我们可以通过sapply()
函数,简化数据,返回一个三行五列的矩阵,如下:
> sapply(s, function(x) {colMeans(x[, c("Ozone", "Solar.R", "Wind")])})
5 6 7 8 9
Ozone NA NA NA NA NA
Solar.R NA 190.16667 216.483871 NA 167.4333
Wind 11.62258 10.26667 8.941935 8.793548 10.1800
其中Ozone
一列数据为NA,这是因为原始数据中有很多NA缺失值,所以,结果也是NA。
怎么去除NA?
给colMeans()
函数传递一个na.rm
参数,从而在每次计算平均值之前先移除每一列的缺失值:
> sapply(s, function(x) {colMeans(x[, c("Ozone", "Solar.R", "Wind")], na.rm = TRUE)})
5 6 7 8 9
Ozone 23.61538 29.44444 59.115385 59.961538 31.44828
Solar.R 181.29630 190.16667 216.483871 171.857143 167.43333
Wind 11.62258 10.26667 8.941935 8.793548 10.18000
Splitting on More than one Level
split
还可以用于基于多个水平的分解:
在前面的例子中,我们只有一个因子变量用于分组,如果我们有多个因子变量,比如性别、种族等,这些因子变量组合起来会产生多个水平,这时怎么办?
举例
创建一个数字向量x,包含10个随机数字,创建两个因子变量f1和f2,分别有2个和5个水平:
> x <- rnorm(10)
> f1 <- gl(2,5)
> f2 <- gl(5,2)
> f1
[1] 1 1 1 1 1 2 2 2 2 2
Levels: 1 2
> f2
[1] 1 1 2 2 3 3 4 4 5 5
Levels: 1 2 3 4 5
使用interaction()
函数,把这两个变量组合起来,就生成了10个水平:
> interaction(f1,f2)
[1] 1.1 1.1 1.2 1.2 1.3 2.3 2.4 2.4 2.5 2.5
Levels: 1.1 2.1 1.2 2.2 1.3 2.3 1.4 2.4 1.5 2.5
所以使用split()
分解数值向量x:
PS. 我们也可以使用list(f1, f2)
,直接把两个因子作为列表传递给因子变量f:
> str(split(x, list(f1, f2)))
List of 10
$ 1.1: num [1:2] -1.01909 -0.00339
$ 2.1: num(0)
$ 1.2: num [1:2] -0.0772 -0.5811
$ 2.2: num(0)
$ 1.3: num -1.68
$ 2.3: num 0.21
$ 1.4: num(0)
$ 2.4: num [1:2] 2.02 -0.96
$ 1.5: num(0)
$ 2.5: num [1:2] -0.172 -0.262
这时我们可以看到,不是每个水平上都有观测值,这是正常的情况,我们也可以设置不显示这些没有元素的分组,使用参数drop = TRUE)
:
> str(split(x, list(f1, f2), drop = TRUE))
List of 6
$ 1.1: num [1:2] -1.01909 -0.00339
$ 1.2: num [1:2] -0.0772 -0.5811
$ 1.3: num -1.68
$ 2.3: num 0.21
$ 2.4: num [1:2] 2.02 -0.96
$ 2.5: num [1:2] -0.172 -0.262
就这样分组完成后,可以使用其他循环函数再进行计算。
上面的结果中,我们用到了一个没见过的函数——str()
,下面介绍一下它。
最重要的查看函数——str()
str()
代表的是structure,用来查看对象内容,是一个简单的诊断函数,可用来替代summary()
我们可以用它来查看大型列表,结构紧凑
> library(datasets)
> str(airquality)
'data.frame': 153 obs. of 6 variables:
$ Ozone : int 41 36 12 18 NA 28 23 19 8 NA ...
$ Solar.R: int 190 118 149 313 NA NA 299 99 19 194 ...
$ Wind : num 7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
$ Temp : int 67 72 74 62 56 66 65 59 61 69 ...
$ Month : int 5 5 5 5 5 5 5 5 5 5 ...
$ Day : int 1 2 3 4 5 6 7 8 9 10 ...
我们也可以用它来查看函数功能,显示参数和概要
> str(lm)
function (formula, data, subset, weights, na.action, method = "qr",
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
contrasts = NULL, offset, ...)
总之我们可以用str()
查看各种对象。
例如,生成一组含有100个正态随机数字的向量,平均值为2,标准差为4,然后通过summary()
函数返回6个概括统计量,分别是最小值、第25百分位数、中位数、平均数、第75百分位数以及最大值,从中粗略的告诉你这个数列的范围以及离散情况:
> x<-rnorm(100, 2, 4)
> summary(x)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-7.6578 0.3534 3.4114 3.1488 5.5520 13.9290
使用str()
函数,他会告诉你x是一个数值向量,含有100个数字
> str(x)
num [1:100] 4.06 3.82 6.28 8.09 2.15 ...
再例如,生成一个10*10的矩阵,用str()
查看
> m <- matrix(rnorm(100), 10, 10)
> str(m)
num [1:10, 1:10] 1.0524 -0.2367 0.0713 0.4177 0.1186 ...
参考资料:
视频课程 R Programming by Johns Hopkins University:https://www.coursera.org/learn/r-programming/home/welcome
讲义 Programming for Data Science :https://bookdown.org/rdpeng/rprogdatascience/R
猜你喜欢
10000+:肠道细菌 人体上的生命 宝宝与猫狗 梅毒狂想曲 提DNA发Nature 实验分析谁对结果影响大 Cell微生物专刊
文献阅读 热心肠 SemanticScholar Geenmedical
16S功能预测 PICRUSt FAPROTAX Bugbase Tax4Fun
写在后面
为鼓励读者交流、快速解决科研困难,我们建立了“宏基因组”专业讨论群,目前己有国内外150+ PI,1500+ 一线科研人员加入。参与讨论,获得专业解答,欢迎分享此文至朋友圈,并扫码加主编好友带你入群,务必备注“姓名-单位-研究方向-职称/年级”。技术问题寻求帮助,首先阅读《如何优雅的提问》学习解决问题思路,仍末解决群内讨论,问题不私聊,帮助同行。
学习16S扩增子、宏基因组科研思路和分析实战,关注“宏基因组”